package com.avic.modules.system.service.impl;

import com.avic.common.service.impl.BaseServiceImpl;
import com.avic.common.utils.QueryHelpPlus;
import com.avic.dozer.service.IGenerator;
import com.avic.exception.BadRequestException;
import com.avic.modules.log.domain.vo.LogEnumeration;
import com.avic.modules.log.domain.vo.LogVo;
import com.avic.modules.log.service.LogsService;
import com.avic.modules.log.utils.ContrastObjUtil;
import com.avic.modules.system.domain.*;
import com.avic.modules.system.domain.vo.RoleVo;
import com.avic.modules.system.service.RoleService;
import com.avic.modules.system.service.RolesDeptsService;
import com.avic.modules.system.service.RolesMenusService;
import com.avic.modules.system.service.UsersRolesService;
import com.avic.modules.system.service.dto.RoleDto;
import com.avic.modules.system.service.dto.RoleQueryCriteria;
import com.avic.modules.system.service.dto.RoleSmallDto;
import com.avic.modules.system.service.dto.UserDto;
import com.avic.modules.system.service.mapper.DeptMapper;
import com.avic.modules.system.service.mapper.MenuMapper;
import com.avic.modules.system.service.mapper.RoleMapper;
import com.avic.modules.system.service.mapper.SysUserMapper;
import com.avic.utils.FileUtil;
import com.avic.utils.SecurityUtils;
import com.avic.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageInfo;
import lombok.AllArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhangzikang
 * @date 2022-08-14
 */
@Service
@AllArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, Role> implements RoleService {

    private final IGenerator generator;
    private final RoleMapper roleMapper;
    private final MenuMapper menuMapper;
    private final DeptMapper deptMapper;
    private final RolesMenusService rolesMenusService;
    private final RolesDeptsService rolesDeptsService;
    private final UsersRolesService usersRolesService;
    private final SysUserMapper sysUserMapper;
    private final LogsService logsService;

    @Override
    public Map<String, Object> queryAll(RoleQueryCriteria criteria, Pageable pageable) {
        getPage(pageable);
        PageInfo<Role> page = new PageInfo<>(queryAll(criteria));
        List<RoleDto> convert = generator.convert(page.getList(), RoleDto.class);
        for(RoleDto zzk:convert){
            User user = sysUserMapper.selectById(zzk.getUpdateUserId());
            if(user!=null){
                zzk.setUpdateUserName(user.getNickName());
            }
            User user2 = sysUserMapper.selectById(zzk.getCreateUserId());
            if(user2!=null) {
                zzk.setCreateUserName(user2.getNickName());
            }
        }
        Map<String, Object> map = new LinkedHashMap<>(2);
        map.put("content", convert);
        map.put("totalElements", page.getTotal());
        return map;
    }

    /**
     * 查询数据分页
     *
     * @param pageable 分页参数
     * @return Object
     */
    @Override
    public Object queryAlls(RoleQueryCriteria criteria, Pageable pageable) {
        List<Role> roleList = baseMapper.selectList(QueryHelpPlus.getPredicate(Role.class, criteria));
        return roleList;
    }


    @Override
    public List<Role> queryAll(RoleQueryCriteria criteria) {
        List<Role> roleList = baseMapper.selectList(QueryHelpPlus.getPredicate(Role.class, criteria));
        for (Role role : roleList) {
            Set<Menu> menuByRoleId = menuMapper.findMenuByRoleId(role.getId());
            Set<Menu> menus = new HashSet<>();
            for(Menu menuBy:menuByRoleId){
                QueryWrapper<Menu> wrapper = new QueryWrapper<>();
                wrapper.eq("pid",menuBy.getId());
                List<Menu> menus1 = menuMapper.selectList(wrapper);
                if(menus1.size()==0){
                    menus.add(menuBy);
                }

            }
            role.setMenus(menus);
            role.setDepts(deptMapper.findDeptByRoleId(role.getId()));
        }
        return roleList;
    }


    @Override
    public void download(List<RoleDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        long sum = 1;
        for (RoleDto role : all) {
            if(role.getUpdateUserId()!=null){
                User user = sysUserMapper.selectById(role.getUpdateUserId());
                if(user!=null){
                    role.setUpdateUserName(user.getNickName());
                }
            }
            if(role.getCreateUserId()!=null){
                User user2 = sysUserMapper.selectById(role.getCreateUserId());
                role.setCreateUserName(user2.getNickName());
            }
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("序号",sum);
            map.put("角色编号", role.getIdentifier());
            map.put("角色名称", role.getName());
            map.put("创建人", role.getCreateUserName());
            if(role.getCreateTime()!=null){
                String s = role.getCreateTime().toString();
                String substring = s.substring(0, s.length() - 2);
                map.put("创建日期", substring);
            } else {
                map.put("创建日期", "");
            }
            map.put("修改人", role.getUpdateUserName());
            if(role.getUpdateTime()!=null){
                String s = role.getUpdateTime().toString();
                String substring = s.substring(0, s.length() - 2);
                map.put("修改日期", substring);
            } else {
                map.put("修改日期", "");
            }
            sum ++;
            list.add(map);
        }
        // 创建操作日志
        String name = "[导出]了"+ "[角色信息]";
        LogVo logVo = new LogVo();
        logVo.setAction(LogEnumeration.LEADING_OUT.getMessage());
        logVo.setBehavior(name);
        logsService.save(logVo);

        FileUtil.downloadExcel(list, response);
    }

    /**
     * 根据用户ID查询
     *
     * @param id 用户ID
     * @return /
     */
    @Override
    public List<RoleSmallDto> findByUsersId(Long id) {
        List<Role> roles = roleMapper.selectListByUserId(id);
        return generator.convert(roles, RoleSmallDto.class);
    }

    /**
     * 根据角色查询角色级别
     *
     * @param roles /
     * @return /
     */
    @Override
    public Integer findByRoles(Set<Role> roles) {
        Set<RoleDto> roleDtos = new HashSet<>();
        for (Role role : roles) {
            roleDtos.add(findById(role.getId()));
        }
        return Collections.min(roleDtos.stream().map(RoleDto::getLevel).collect(Collectors.toList()));
    }

    /**
     * 根据ID查询
     *
     * @param id /
     * @return /
     */
    @Override
    public RoleDto findById(long id) {
        Role role = this.getById(id);
        role.setMenus(menuMapper.findMenuByRoleId(role.getId()));
        role.setDepts(deptMapper.findDeptByRoleId(role.getId()));
        return generator.convert(role, RoleDto.class);
    }

    /**
     * 修改绑定的菜单
     *
     * @param resources /
     * @param roleDto   /
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateMenu(Role resources, RoleDto roleDto) {

        resources.setUpdateUserId(SecurityUtils.getUserId());

        // 查询修改了那个角色的权限
        Role role = roleMapper.selectById(resources.getId());
        Set<Menu> menuByRoleId = menuMapper.findMenuByRoleId(resources.getId());
        // 修改前过滤数据
        String string = "";
        for(Menu menu:menuByRoleId){
            string +=menu.getName() + ",";
        }

        // 修改后过滤数据
        List<String> data = new ArrayList<>();
        List<RolesMenus> rolesMenusList = resources.getMenus().stream().map(i -> {
            RolesMenus rolesMenus = new RolesMenus();
            rolesMenus.setRoleId(resources.getId());
            rolesMenus.setMenuId(i.getId());
            Menu menu2 = menuMapper.selectById(i.getId());
            data.add(menu2.getName());
            return rolesMenus;
        }).collect(Collectors.toList());
        rolesMenusService.remove(new LambdaQueryWrapper<RolesMenus>().eq(RolesMenus::getRoleId, resources.getId()));
        rolesMenusService.saveBatch(rolesMenusList);


        // 对比修改了哪些权限
        String total = "";
        for(String sum:data){
            total += sum + ",";
        }

        // 创建操作日志
        String s = ContrastObjUtil.comparObj(total,string);
        String name = "[修改]了"+ " [" + role.getName() + "] " + "角色权限 ";
        LogVo logVo = new LogVo();
        logVo.setInformation(s);
        logVo.setAction(LogEnumeration.MODIFY.getMessage());
        logVo.setBehavior(name);
        logsService.save(logVo);
    }

    /**
     * 添加角色信息
     * @param resources /
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public RoleDto create(Role resources) {
        String stt = "[0-9]{1,10}";
        if(!resources.getIdentifier().matches(stt)){
            throw new BadRequestException("角色编号只能是数字");
        }

        QueryWrapper<Role> wrapper = new QueryWrapper<>();
        wrapper.eq("identifier",resources.getIdentifier());
        Role role = roleMapper.selectOne(wrapper);
        if(role!=null){
            if(resources.getId()!=role.getId()){
                throw new BadRequestException("角色编号不能重复");
            }
        }

        QueryWrapper<Role> wrapper2 = new QueryWrapper<>();
        wrapper2.eq("name",resources.getName());
        Role role2 = roleMapper.selectOne(wrapper2);
        if(role2!=null){
            if(resources.getId()!=role2.getId()){
                throw new BadRequestException("角色名称不能重复");
            }
        }

        try {
            resources.setUpdateTime(new Timestamp(System.currentTimeMillis()));
            resources.setCreateTime(new Timestamp(System.currentTimeMillis()));
            resources.setCreateUserId(SecurityUtils.getUserId());
        } catch (BadRequestException e) {
            throw new BadRequestException("登录状态已过期");
        }

        resources.setLevel(1);
        this.save(resources);
        if (resources.getDepts().size() > 0) {
            List<RolesDepts> rolesDeptsList = resources.getDepts().stream().map(i -> {
                RolesDepts rolesDepts = new RolesDepts();
                rolesDepts.setRoleId(resources.getId());
                rolesDepts.setDeptId(i.getId());
                return rolesDepts;
            }).collect(Collectors.toList());
            rolesDeptsService.saveBatch(rolesDeptsList);
        }

        // 创建操作日志
        String name = "[添加]了"+ " [" + resources.getIdentifier()+ "] " +"角色信息";
        LogVo logVo = new LogVo();
        logVo.setAction(LogEnumeration.Add_TO.getMessage());
        logVo.setBehavior(name);
        logsService.save(logVo);

        return generator.convert(resources, RoleDto.class);
    }

    /**
     * 修改角色信息
     * @param resources /
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Role resources) {

        String stt = "[0-9]{1,10}";
        if(!resources.getIdentifier().matches(stt)){
            throw new BadRequestException("角色编号只能是数字");
        }

        QueryWrapper<Role> wrapper = new QueryWrapper<>();
        wrapper.eq("identifier",resources.getIdentifier());
        Role role = roleMapper.selectOne(wrapper);
        if(role!=null){
            if(resources.getId()!=role.getId()){
                throw new BadRequestException("角色编号不能重复");
            }
        }
        QueryWrapper<Role> wrapper2 = new QueryWrapper<>();
        wrapper2.eq("name",resources.getName());
        Role role2 = roleMapper.selectOne(wrapper2);
        if(role2!=null){
            if(resources.getId()!=role2.getId()){
                throw new BadRequestException("角色名称不能重复");
            }
        }


        // 修改后的过滤数据
        RoleVo roleVo = new RoleVo();
        roleVo.setIdentifier(resources.getIdentifier());
        roleVo.setName(resources.getName());
        if(resources.getRemark()!=null){
            roleVo.setRemark(resources.getRemark());
        } else {
            roleVo.setRemark(null);
        }

        // 修改前的过滤数据
        RoleVo vo = new RoleVo();
        Role role1 = roleMapper.selectById(resources.getId());
        vo.setIdentifier(role1.getIdentifier());
        vo.setName(role1.getName());
        if(role1.getRemark()!=null){
            vo.setRemark(role1.getRemark());
        } else {
            vo.setRemark(null);
        }

        if (resources.getDepts().size() > 0) {
            List<RolesDepts> rolesDeptsList = resources.getDepts().stream().map(i -> {
                RolesDepts rolesDepts = new RolesDepts();
                rolesDepts.setRoleId(resources.getId());
                rolesDepts.setDeptId(i.getId());
                return rolesDepts;
            }).collect(Collectors.toList());
            rolesDeptsService.remove(new LambdaQueryWrapper<RolesDepts>().eq(RolesDepts::getRoleId, resources.getId()));
            rolesDeptsService.saveBatch(rolesDeptsList);
        }
        try {
            resources.setUpdateTime(new Timestamp(System.currentTimeMillis()));
            resources.setUpdateUserId(SecurityUtils.getUserId());
        } catch (BadRequestException e) {
            throw new BadRequestException("登录状态已过期");
        }
        this.saveOrUpdate(resources);
        // 创建操作日志
        String s = ContrastObjUtil.comparObj(roleVo,vo);
        String name = "[修改]了"+ " [" + role1.getName() + "] " + "角色信息 ";
        LogVo logVo = new LogVo();
        logVo.setInformation(s);
        logVo.setAction(LogEnumeration.MODIFY.getMessage());
        logVo.setBehavior(name);
        logsService.save(logVo);
    }

    /**
     * 获取用户权限信息
     *
     * @param user 用户信息
     * @return 权限信息
     */
    @Override
    public Collection<SimpleGrantedAuthority> mapToGrantedAuthorities(UserDto user) {
        Set<Role> roles = roleMapper.findByUsers_Id(user.getId());
        for (Role role : roles) {
            Set<Menu> menuSet = menuMapper.findMenuByRoleId(role.getId());
            role.setMenus(menuSet);
            Set<Dept> deptSet = deptMapper.findDeptByRoleId(role.getId());
            role.setDepts(deptSet);
        }
        Set<String> permissions = roles.stream().filter(role -> StringUtils.isNotBlank(role.getPermission())).map(Role::getPermission).collect(Collectors.toSet());
        permissions.addAll(
                roles.stream().flatMap(role -> role.getMenus().stream())
                        .filter(menu -> StringUtils.isNotBlank(menu.getPermission()))
                        .map(Menu::getPermission).collect(Collectors.toSet())
        );
        return permissions.stream().map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Set<Long> ids) {
        List<String> strings = new ArrayList<>();
        for (Long id : ids) {
            rolesMenusService.lambdaUpdate().eq(RolesMenus::getRoleId, id).remove();
            rolesDeptsService.lambdaUpdate().eq(RolesDepts::getRoleId, id).remove();
            usersRolesService.lambdaUpdate().eq(UsersRoles::getRoleId, id).remove();
            Role role = roleMapper.selectById(id);
            strings.add(role.getIdentifier());
        }
        this.removeByIds(ids);

        // 创建操作日志
        String name = "[删除]了"+ " [" + strings.toString() + "] " +"角色信息";
        LogVo logVo = new LogVo();
        logVo.setAction(LogEnumeration.Delete.getMessage());
        logVo.setBehavior(name);
        logsService.save(logVo);
    }

}
